﻿#include "CFDPostTreeWidget.h"

#include "CFDPostOperatorsInterface/CFDPostGraphEventOperator.h"
#include "CFDPostDataManager/CFDPostDataManager.h"

#include "OperatorsInterface/ParaWidgetInterfaceOperator.h"
#include "OperatorsInterface/GraphEventOperator.h"
#include "PostGraphAdaptor/PostGraphObjectManager.h"
#include "PostGraphAdaptor/PostGraphObjectBase.h"

#include "FITK_Kernel/FITKCore/FITKOperatorRepo.h"
#include "FITK_Kernel/FITKCore/FITKActionOperator.h"

#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Interface/FITKInterfaceCFDPost/FITKCFDPostEnum.h"
#include "FITK_Interface/FITKInterfaceCFDPost/FITKAbstractCFDPostData.h"
#include "FITK_Interface/FITKInterfaceCFDPost/FITKCFDPost3DManager.h"
#include "FITK_Interface/FITKInterfaceCFDPost/FITKCFDPostData.h"

#include "CFDPostUtils/CFDPostSigsCenter.h"

#include <QMenu>

#define TreeItemPostDataID Qt::UserRole+1
#define TreeItemType Qt::UserRole+2

Q_DECLARE_METATYPE(Interface::FITKPostDataType)

namespace GUI {
    CFDPostTreeWidget::CFDPostTreeWidget(QWidget* parent) :
        QTreeWidget(parent) {
        _postDataManager = FITKAPP->getGlobalData()->getPostData<Interface::FITKCFDPostData>()->getPostDataManager();
        _postGraphManager = Interface::PostGraphObjectManager::getInstance();

        //右键 不可少否则右键无反应
        setContextMenuPolicy(Qt::CustomContextMenu);
        connect(this, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(slotItemClecked(QTreeWidgetItem*, int)));
        connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onModelCustomContextMenu(QPoint)));

        //隐藏列标题
        setHeaderHidden(true);

        updateTree();
    }

    CFDPostTreeWidget::~CFDPostTreeWidget() {
        if (_rootItem != nullptr) {
            _rootItem->takeChildren();
        }
    }

    void CFDPostTreeWidget::updateTree() {
        this->clear();
        _itemHash.clear();

        _rootItem = new QTreeWidgetItem;
        _rootItem->setText(0, "Graph Object");
        this->addTopLevelItem(_rootItem);
        QTreeWidgetItem* currentItem = nullptr;
        QTreeWidgetItem* firstItem = nullptr;

        for (int i = 0; i < _postDataManager->getDataCount(); i++) {
            Interface::FITKAbstractCFDPostData* postData = _postDataManager->getDataByIndex(i);

            if (postData == nullptr) {
                continue;
            }

            int dataID = postData->getDataObjectID();
            int parentID = postData->getCFDPostParentID();
            QString dataName = postData->getDataObjectName();
            QTreeWidgetItem* parentItem = _itemHash.value(parentID);
            QTreeWidgetItem* item = nullptr;

            if (parentItem) {
                item = new QTreeWidgetItem(parentItem);
            } else {
                item = new QTreeWidgetItem(_rootItem);
            }

            _itemHash.insert(dataID, item);

            if (i == 0) {
                firstItem = item;
            }

            if (_currentObjID == dataID) {
                currentItem = item;
            }

            Qt::CheckState state = Qt::Checked;

            if (postData->isEnable() == false) {
                state = Qt::Unchecked;
            }

            item->setText(0, dataName);
            item->setData(0, TreeItemPostDataID, dataID);
            Interface::FITKPostDataType type = postData->getPostDataType();
            item->setData(0, TreeItemType, QVariant::fromValue(type));
            item->setCheckState(0, state);
        }

        //展开全部子集
        setItemsExpandable(true);
        expandAll();

        if (currentItem) {
            setCurrentItem(currentItem);
            slotItemClecked(currentItem, 0);
        } else {
            setCurrentItem(firstItem);
            slotItemClecked(firstItem, 0);
        }
    }

    int CFDPostTreeWidget::getCurrentDataID() {
        return _currentObjID;
    }

    void CFDPostTreeWidget::slotItemClecked(QTreeWidgetItem * item, int index) {
        Q_UNUSED(index);

        if (item == nullptr) {
            return;
        }

        int objID = item->data(0, TreeItemPostDataID).toInt();
        // _currentObjID = objID;
        this->setCurrentDataID(objID);
        Interface::FITKPostDataType type = item->data(0, TreeItemType).value<Interface::FITKPostDataType>();
        QString actionName = "";
        QMenu menu;

        if (!actionName.isEmpty()) {
            QObject sender;
            sender.setObjectName(actionName);
            auto acOper = Core::FITKOperatorRepo::getInstance()->getOperatorT<Core::FITKActionOperator>(actionName);

            if (acOper == nullptr) {
                return;
            }

            acOper->setEmitter(&sender);
            acOper->setArgs("objID", objID);
            acOper->actionTriggered();
        }

        //更新渲染窗口
        bool show = (item->checkState(0) == Qt::Checked);
        EventOper::CFDPostGraphEventOperator* graphOper =
            FITKOPERREPO->getOperatorT<EventOper::CFDPostGraphEventOperator>("OperGraphPreprocess");

        if (graphOper == nullptr) {
            return;
        }

        graphOper->updateShow(objID, show);
        graphOper->reRender();

        emit CFDPostSigsCenter::getInstance()->sig_postTreeSelectedChanged(objID);
        //        //更新信息界面
        ////        EventOper::ParaWidgetInterfaceOperator* infoOper = FITKOPERREPO->getOperatorT<EventOper::ParaWidgetInterfaceOperator>("OperatorsWidget");
        //        OperGUI::OperatorsWidget* infoOper = FITKOPERREPO->getOperatorT<OperGUI::OperatorsWidget>("OperatorsWidget");
        //        if (infoOper) {
        //            infoOper->CurrentObjectChange(objID);
        //        }
    }

    void CFDPostTreeWidget::onModelCustomContextMenu(QPoint point) {
        Q_UNUSED(point);

        QTreeWidgetItem* item = this->currentItem();

        if (item == nullptr) {
            return;
        }

        int curItemChildNum = item->childCount();
        int objID = item->data(0, TreeItemPostDataID).toInt();
        Interface::FITKPostDataType type = item->data(0, TreeItemType).value<Interface::FITKPostDataType>();
        QString actionName = "";
        QMenu menu;

        //删除是否可用
        bool deleteIsEnable = true;

        if (curItemChildNum > 0) {
            deleteIsEnable = false;
        }

        switch (type) {
            case Interface::FITKPostDataType::Post_None:
                break;

            case Interface::FITKPostDataType::Post_Steady:
                addMenuActions(menu, "actionGraphDelete", "Delete", deleteIsEnable);
                break;

            case Interface::FITKPostDataType::Post_UnSteady:
                addMenuActions(menu, "actionGraphDelete", "Delete", deleteIsEnable);
                break;

            case Interface::FITKPostDataType::Post_Isosurface:
                addMenuActions(menu, "actionGraphDelete", "Delete", deleteIsEnable);
                addMenuActions(menu, "actionIsosurfEdit", "Edit");
                break;

            case Interface::FITKPostDataType::Post_ClipPlane:
            case Interface::FITKPostDataType::Post_ClipSphere:
            case Interface::FITKPostDataType::Post_ClipCylinder:
            case Interface::FITKPostDataType::Post_ClipBox:
                addMenuActions(menu, "actionGraphDelete", "Delete", deleteIsEnable);
                addMenuActions(menu, "actionClipEdit", "Edit");
                break;

            case Interface::FITKPostDataType::Post_SlicePlane:
            case Interface::FITKPostDataType::Post_SliceSphere:
            case Interface::FITKPostDataType::Post_SliceCylinder:
            case Interface::FITKPostDataType::Post_SliceBox:
                addMenuActions(menu, "actionGraphDelete", "Delete", deleteIsEnable);
                addMenuActions(menu, "actionSliceEdit", "Edit");
                break;

            case Interface::FITKPostDataType::Post_StreamLine:
                addMenuActions(menu, "actionGraphDelete", "Delete", deleteIsEnable);
                addMenuActions(menu, "actionStreamlineEdit", "Edit");
                break;

            case Interface::FITKPostDataType::Post_Glyph:
                addMenuActions(menu, "actionGraphDelete", "Delete", deleteIsEnable);
                addMenuActions(menu, "actionGlyphEdit", "Edit");
                break;

            case  Interface::FITKPostDataType::Post_Threshold:
                addMenuActions(menu, "actionGraphDelete", "Delete", deleteIsEnable);
                addMenuActions(menu, "actionThresholdEdit", "Edit");
                break;

            case Interface::FITKPostDataType::Post_Deform:
                addMenuActions(menu, "actionGraphDelete", "Delete", deleteIsEnable);
                addMenuActions(menu, "actionDeformEdit", "Edit");
                break;

            case Interface::FITKPostDataType::Post_Probe:
                addMenuActions(menu, "actionGraphDelete", "Delete", deleteIsEnable);
                addMenuActions(menu, "actionProbeEdit", "Edit");
                break;
        }

        if (menu.actions().size() == 0) {
            return;
        }

        // 在鼠标点击位置执行上下文菜单
        menu.exec(QCursor::pos());
    }

    void CFDPostTreeWidget::slotAcitonClicked() {
        QTreeWidgetItem* item = this->currentItem();

        if (item == nullptr) {
            return;
        }

        int objID = item->data(0, TreeItemPostDataID).toInt();

        QObject* senderObject = sender();

        if (senderObject == nullptr) {
            return;
        }

        auto acOper = Core::FITKOperatorRepo::getInstance()->getOperatorT<Core::FITKActionOperator>(senderObject->objectName());

        if (acOper == nullptr) {
            return;
        }

        acOper->setEmitter(senderObject);
        acOper->setArgs("objID", objID);
        acOper->actionTriggered();
    }

    void CFDPostTreeWidget::addMenuActions(QMenu & menu, QString actions, QString objectName, bool isEnable) {
        QAction* act = menu.addAction(objectName); // 添加动作
        act->setObjectName(actions);
        act->setEnabled(isEnable);
        connect(act, SIGNAL(triggered()), this, SLOT(slotAcitonClicked()));
    }

    void CFDPostTreeWidget::setCurrentDataID(int dataID) {
        // 保持ID
        _currentObjID = dataID;
        // 提供给 数据中心一份！供其它模块使用
        DataManager::CFDPostDataManager::getInstance()->setTreeCurrentDataID(_currentObjID);
    }
} // namespace GUI
